package com.lagou.niancheng.core.session.defaults;


import com.lagou.niancheng.core.config.BoundSql;
import com.lagou.niancheng.core.config.MappedStatement;
import com.lagou.niancheng.core.config.MethodMetaData;
import com.lagou.niancheng.core.result.ResultSetConverter;
import com.lagou.niancheng.core.session.Executor;
import com.lagou.niancheng.core.transaction.TransactionManager;
import com.lagou.niancheng.core.utils.ParameterMapping;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;

public class DefaultExecutor implements Executor {

    private TransactionManager transactionManager;
    private ResultSetConverter resultSetConverter;

    public DefaultExecutor(ResultSetConverter resultSetConverter, TransactionManager transactionManager) {
        this.resultSetConverter = resultSetConverter;
        this.transactionManager = transactionManager;
    }

    @Override
    public List<Object> query(MappedStatement mappedStatement, Object... params) throws Exception {
        // 1.获取连接
        Connection connection = transactionManager.getConnection();
        // 2.执行语句
        ResultSet resultSet = prepareStatement(connection, mappedStatement, params).executeQuery();
        // 3.结果解析
        return resultSetConverter.converter(mappedStatement, resultSet);
    }

    @Override
    public void update(MappedStatement mappedStatement, Object... params) throws Exception {
        // 1.获取事务连接
        Connection connection = transactionManager.openTransaction();
        // 2.执行语句
        prepareStatement(connection, mappedStatement, params).execute();
    }

    @Override
    public void insert(MappedStatement mappedStatement, Object... params) throws Exception {
        // 1.获取事务连接
        Connection connection = transactionManager.openTransaction();
        // 2.执行语句
        prepareStatement(connection, mappedStatement, params).execute();
    }

    @Override
    public void delete(MappedStatement mappedStatement, Object... params) throws Exception {
        // 1.获取事务连接
        Connection connection = transactionManager.openTransaction();
        // 2.执行语句
        prepareStatement(connection, mappedStatement, params).execute();
    }


    /**
     * 执行语句
     *
     * @param connection      数据库连接
     * @param mappedStatement 映射语句
     * @param params          参数
     * @return 返回数据库执行结果
     * @throws Exception
     */
    private PreparedStatement prepareStatement(Connection connection, MappedStatement mappedStatement, Object... params) throws Exception {
        // 1.获取boundSql语句
        BoundSql boundSql = mappedStatement.getBoundSql();
        // 2.获取预处理对象：preparedStatement
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
        // 3. 设置参数
        //获取到了参数的全路径
        Class parameterType = mappedStatement.getParameterType();
        MethodMetaData methodMetaData = mappedStatement.getMethodMetaData();
        List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
        for (int i = 0; i < parameterMappingList.size(); i++) {
            ParameterMapping parameterMapping = parameterMappingList.get(i);
            String content = parameterMapping.getContent();
            Object param;
            // 如果有方法原数据，直接使用方法原数据获取参数
            if (methodMetaData != null) {
                param = methodMetaData.getParam(content, params);
            } else {
                //反射
                Field declaredField = parameterType.getDeclaredField(content);
                //暴力访问
                declaredField.setAccessible(true);
                param = declaredField.get(params[0]);
            }
            preparedStatement.setObject(i + 1, param);
        }

        // 4. 执行sql
        return preparedStatement;
    }


}
